<?php
/**
 * 登录
 * User: cxm
 * Date: 2020/8/11
 * Time: 18:04
 */
namespace App\Http\Controllers\Home;
use App\Http\Controllers\Common\DecryptController;
use App\Models\LoginLog;
use App\Models\SmsCode;
use App\Models\User;
use App\Models\UserStepRecord;
use App\Models\UserWeixin;
use App\Utils\LogUtils;
use Carbon\Carbon;
use EasyWeChat\Factory;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

class LoginController extends Controller {
    /**
     * 获取微信 openid
     * @param string $code
     * @return string
     * @throws
     */
    public function GetOpenid($code=''){
        $config = [
            'app_id' => config('wechat.mini_program.default.app_id'),
            'secret' => config('wechat.mini_program.default.secret'),

            // 下面为可选项
            // 指定 API 调用返回结果的类型：array(default)/collection/object/raw/自定义类名
            'response_type' => 'array',

            'log' => [
                'level' => 'debug',
                'file' => __DIR__.'/wechat.log',
            ],
        ];
        $app = Factory::miniProgram($config);
        //这个code值是前端访问的网址，返回的。微信返回的openid和session_key以及unionid
        //（unionid不一定返回，openid和session_key肯定会返回把它们两个先存到用户表中）
        $wx = $app->auth->session($code);

//       $res = isset($wx['openid'])?$wx['openid']:'';
        if (intval(session('user_wx_session')) <  time()- 3*86400 ) {
            Session::put('user_wx_session',time());
            Session::put('user_wx_session_key',$wx['session_key']);
        }
        return $wx;
    }

    /**
     * 获取openid
     * URL POST:/api/home/getOpenid
     * @param Request $request
     * @param string code 微信id
     * @return mixed
     */
    public function openid(Request $request){
        $params = $request->only(['code']);
        if (!isset($params['code']) || empty($params['code'])) {
            return $this->error('code不存在');
        }
        $res = $this->GetOpenid($params['code']);
        $openid = $res['openid'];
        if (!$openid) {
            return $this->error('获取openid失败');
        }
        // 根据openid查询用户
        $user_weixin = UserWeixin::where('openid',$openid)->first();
        if ($user_weixin) {
            if ($user_weixin->user_id > 0) {
                $user = User::find($user_weixin->user_id);
                if (!$user) {
                    $data = [
                        'type'       => 2,
                        'openid'     => $openid,
                    ];
                    return $this->success('获取成功',compact('data'));
                }else{
                    $token = auth('api')->tokenById($user_weixin->user_id);
                    $data = [
                        'type'      => 1,
                        'user_id'   => $user_weixin->user_id,
                        'token'     => $token
                    ];
                    return $this->success('登录成功',compact('data'));
                }
            }else{
                $data = [
                    'type'       => 2,
                    'openid'     => $openid,
                ];
                return $this->success('获取成功',compact('data'));
            }
        }else{
            $data = [
                'type'       => 2,
                'openid'     => $openid
            ];
            return $this->success('获取成功',compact('data'));
        }
    }

    /**
     * 微信授权获取手机
     * URL POST:/api/home/weixinMobile
     * @param Request $request
     * @param string encryptedData 包括敏感数据在内的完整用户信息的加密数据
     * @param string iv 加密算法的初始向量
     * @param string code
     * @return mixed
     */
    public function weixinGetMobile(Request $request){
        $params = $request->only(['encryptedData','iv','code']);
        $validator = Validator::make($params,[
            'encryptedData'        => ['required'],
            'iv'                   => ['required'],
            'code'                 => ['required']
        ],[
            'encryptedData.required'   => '用户信息的加密数据不能为空',
            'iv.required'              => '加密算法的初始向量不能为空',
            'code.required'            => 'code不能为空'
        ]);
        if ($validator->fails()) {
            return $this->error($validator->errors()->first());
        }
        // 根据code获取用户信息
        $info = $this->GetOpenid($params['code']);
        if (empty($info)) {
            return $this->error('获取session_key失败');
        }
        $decry = new DecryptController('customer',session('user_wx_session_key'));
        $errCode = $decry->decryptData($params['encryptedData'],$params['iv'],$data);

        // 返回的data信息
        // {
        //    "phoneNumber": "13580006666",//用户绑定的手机号（国外手机号会有区号）
        //    "purePhoneNumber": "13580006666",//没有区号的手机号
        //    "countryCode": "86",//区号
        //    "watermark":
        //    {
        //        "appid":"APPID",
        //        "timestamp": TIMESTAMP
        //    }
        //}
        if ($errCode != 0) {
            return $this->error($errCode);
        }
        $data = json_decode($data,true);

        $mobile = $data['phoneNumber'];
        if ( !$mobile) {
            return $this->error('手机获取失败');
        }
        return $this->success('获取成功',$mobile);
    }

    /**
     * 根据手机匹配用户
     * URL POST:/api/home/getUserByMobile
     * @param Request $request
     * @param string mobile 手机号
     * @return mixed
     */
    public function getUserByMobile(Request $request){
        $params = $request->only(['mobile']);
        if (!array_key_exists('mobile',$params) || empty($params['mobile'])) {
            return $this->error('缺少手机号');
        }
        $user = User::where('mobile',$request['mobile'])->first();
        if (!$user) {
            return $this->error('号码不存在，去联系相关负责人进行登记。');
        }
        $token = auth('api')->tokenById($user['id']);
        return $this->success('匹配成功',$token);
    }

    /**
     * 用户报名--匹配用户
     * URL POST:/api/home/userEnlist
     * @param Request $request
     * @param string openid 用户openid
     * @param string username 姓名
     * @param string mobile 手机
     * @param string nickName 昵称
     * @param int gender 性别
     * @param string city 城市
     * @param string province 省
     * @param string country 国家
     * @param string language 语言
     * @param string avatarUrl 头像
     * @return mixed
     */
    public function userEnlist(Request $request) {
        $params = $request->only(['openid','username','mobile','nickName','gender','city','province','country','language','avatarUrl']);
        LogUtils::log('报名时接收参数：'.json_encode($params),'sign','sign_param');
        $validator = Validator::make($params,[
            'openid'            => ['required'],
            'username'          => ['required'],
            'mobile'            => ['required','regex:/^1[3456789]\d{9}$/'],
        ],[
            'openid.required'       => 'openid是必须的',
            'username.required'     => '用户名称是必须的',
            'mobile.required'       => '用户手机是必须的',
            'mobile.regex'          => '手机格式错误',
        ]);
        if ($validator->fails()) {
            return $this->error($validator->errors()->first());
        }
        // 查看名称与手机是否存在
        $where[] = ['name',$params['username']];
        $where[] = ['mobile',$params['mobile']];
        $res = User::detail($where);
        if ($res) {
            $user_id = $res['id'];
        }else{
            return $this->error('号码不存在，去联系相关负责人进行登记。');
        }
        if (!$user_id) {
            return $this->error('程序错误');
        }
        // 判断用户是否绑定
        $user_info = UserWeixin::where('user_id',$user_id)->first();
        if ($user_info) {
            return $this->error('用户已经绑定');
        }
        // 存入用户的微信
        $user_weixin = UserWeixin::where('openid',$params['openid'])->first();
        if (!$user_weixin) {
            $user_weixin = new UserWeixin();
        }
        $user_weixin->user_id = $user_id;
        $user_weixin->openid = $params['openid'];
        $user_weixin->nickname = isset($params['nickName']) ? $params['nickName'] : '';
        $user_weixin->sex = $params['gender'];
        $user_weixin->city = isset($params['city']) ? $params['city'] : '';
        $user_weixin->province = isset($params['province']) ? $params['province'] : '';
        $user_weixin->country = isset($params['country']) ? $params['country'] : '';
        $user_weixin->language = $params['language'];
        $user_weixin->headimgurl = isset($params['avatarUrl']) ? $params['avatarUrl'] : '';
        $result = $user_weixin->save();
        if ($result === false) {
            return $this->error('微信新储存失败');
        }
        // 修改用户报名时间
        User::where('id',$user_id)->update(['sign_time'=>Carbon::now()]);
        $token = auth('api')->tokenById($user_id);
        return $this->success('查询成功',$token);
    }

    /**
     * 用户步数
     * URL POST:/api/home/steps
     * @param Request $request
     * @param string code
     * @param string encryptData
     * @param string iv
     * @return mixed
     */
    public function steps(Request $request){
        $params = $request->only(['code','encryptData','iv']);
        // 根据code获取openid和sessionKey  通过sessionKey解密获取unionID与微信授权用户信息
        $info = $this->GetOpenid($params['code']);
        if (empty($info)) {
            return $this->error('获取session_key失败');
        }
        //\Log::info('用户openid和session_key信息：'.json_encode($info).' session_key:'.session('user_wx_session_key'));
        $decry = new DecryptController(session('user_wx_session_key'));
        $errCode = $decry->decryptData($params['encryptData'],$params['iv'],$data);
        //\Log::info('返回结果：'. $errCode .'    解密后微信用户信息：'.$data);
        if ($errCode !== 0) {
            return $this->error($errCode);
        }
        $data = json_decode($data,true);
        if (empty($data)) {
            return $this->error('微信信息获取失败');
        }
        // 数组排序
        array_multisort(array_column($data['stepInfoList'], 'timestamp'), SORT_DESC, $data['stepInfoList']);
        // 用户步数
        $steps = $data['stepInfoList'][0]['step'];
        // 用户信息
        $user = $this->userModel();
        $where = [];
        $where[] = ['user_id',$user['id']];
        $where[] = ['date',date('Y-m-d')];
        // 记录用户步数
        $userSteps = UserStepRecord::where($where)->first();
        if ($userSteps) {
            UserStepRecord::where($where)->update(['steps'=>$steps]);
        }else{
            UserStepRecord::insert([
                'user_id'       => $user['id'],
                'date'          => date('Y-m-d'),
                'steps'         => $steps,
                'created_at'    => Carbon::now()
            ]);
        }
        return $this->success('成功',$steps);
    }

    /**
     * 生成个人二维码
     * @param $user_id
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException
     */
    public function createdQrcode($user_id){
        // 生成个人二维码
        $config = config('wechat.mini_program.default');
        $app = Factory::miniProgram($config);

        $response = $app->app_code->getUnlimit("user_id={$user_id}",['width'=>100]);

        if ($response instanceof \EasyWeChat\Kernel\Http\StreamResponse) {
            $filename = $response->saveAs('qrcodes/user','user_qrcode_'.$user_id.'.png');
        }
//        // 上传到OSS
//        $file = OssUpload('qrcodes/user/',$filename,'png'); $file['oss_path']
        $path =  'qrcodes/user/user_qrcode_'.$user_id.'.png';
        User::where('id',$user_id)->update(['qr_code'=>$path]);
    }

    /**
     * 获取客户端真实ip
     * @return mixed
     */
    protected function _getRealIpAddr() {
        if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
            $ip=$_SERVER['HTTP_CLIENT_IP'];
        } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { //to check ip is pass from proxy
            $ip=$_SERVER['HTTP_X_FORWARDED_FOR'];
        } else {
            $ip=$_SERVER['REMOTE_ADDR'];
        }

        return $ip;
    }

    /**
     * 退出登录
     * URL POST:/api/home/logout
     * @return mixed
     */
    public function logout(){
        try {
            // 获取当前用户
            $user_id = Auth::guard('api')->user()->id;

            // 查询最后一条登录记录
            $login_log = LoginLog::where('type',1)->where('user_id',$user_id)->orderBy('time','desc')->first();

            // 获取登录时长
            $login_time = strtotime($login_log->time);

            $login_length = time() - $login_time;

            // 修改登录日志
            LoginLog::where('id',$login_log->id)->update([
                'out_time'      => Carbon::now(),
                'length_time'   => $login_length
            ]);

            Auth::guard('api')->logout();
        } catch (\Exception $e) {

            return $this->_error('退出失败，请重试');
        }

        return $this->_success('退出成功');
    }
}